package com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.repository;

import java.text.ParseException;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.ProcessInstanceLinkStatusEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.ProcessInstanceStatusEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.TaskLinkStatusEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.FlowCatalogueService;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.UserService;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.*;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.monitor.HttpProcessInstanceQueryVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.monitor.ProcessInstanceQueryVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.statistics.ProcessInstanceStatisticsQueryVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.task.FlowExecutionQueryVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowProcessInstanceOperateTraceRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowProcessInstanceTraceRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowTaskTraceRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.UserRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.entities.FlowProcessInstanceTrace;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.entities.FlowProcessInstanceTraceExample;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.entities.FlowTaskTrace;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.mapper.FlowExecutionQueryDAO;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.mapper.FlowProcessInstanceTraceDAO;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.mapper.FlowTaskTraceDAO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.flowable.engine.common.impl.cfg.IdGenerator;
import org.flowable.engine.common.impl.util.CollectionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author lilh
 * @date 2019-05-05 14:09
 */
@Service
@Slf4j
public class FlowProcessInstanceTraceRepositoryImpl implements FlowProcessInstanceTraceRepository {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private FlowProcessInstanceTraceDAO flowProcessInstanceTraceDAO;

    @Autowired
    private IdGenerator idGenerator;

    @Autowired
    private FlowCatalogueService catalogueService;

    @Autowired
    private FlowTaskTraceRepository taskTraceRepository;

    @Autowired
    private FlowExecutionQueryDAO flowExecutionQueryDAO;
    @Autowired
    private UserRepository userRepository;

    @Autowired
    private FlowTaskTraceDAO flowTaskTraceDAO;

    @Autowired
    private UserService userService;

    @Autowired
    private FlowProcessInstanceOperateTraceRepository flowProcessInstanceOperateTraceRepository;

    @Override
    public int insertProcessInstanceTrace(FlowProcessInstanceTraceVo vo) {
        vo.setId(idGenerator.getNextId());
        FlowProcessInstanceTrace entity = new FlowProcessInstanceTrace();
        BeanUtils.copyProperties(vo, entity);
        return flowProcessInstanceTraceDAO.insertSelective(entity);
    }

    @Override
    public FlowProcessInstanceTraceVo getProcessInstanceTraceByProcessInstanceId(String processInstanceId) {
        FlowProcessInstanceTraceExample query = new FlowProcessInstanceTraceExample();
        query.createCriteria().andProcessInstanceIdEqualTo(processInstanceId);
        List<FlowProcessInstanceTrace> flowProcessInstanceTraces = flowProcessInstanceTraceDAO.selectByExample(query);
        if (flowProcessInstanceTraces.size() > 0) {
            return convert(flowProcessInstanceTraces.get(0));
        }
        return null;
    }

    @Override
    public List<FlowProcessInstanceTraceVo> getProcessInstanceTraces(ProcessInstanceStatisticsQueryVo processInstanceStatisticsQueryVo) {

        if (catalogueService.checkTenantAuthorize(processInstanceStatisticsQueryVo)) {
            return Collections.emptyList();
        }

        FlowProcessInstanceTraceExample query = new FlowProcessInstanceTraceExample();
        FlowProcessInstanceTraceExample.Criteria criteria = query.createCriteria();
        query.setOrderByClause(" start_time desc");


        if (Objects.nonNull(processInstanceStatisticsQueryVo.getTenantId())) {
            criteria.andTenantIdEqualTo(processInstanceStatisticsQueryVo.getTenantId());
        }

        if (CollectionUtils.isNotEmpty(processInstanceStatisticsQueryVo.getTenantIds())) {
            criteria.andTenantIdIn(processInstanceStatisticsQueryVo.getTenantIds());
        }

        if (Objects.nonNull(processInstanceStatisticsQueryVo.getAppId())) {
            criteria.andAppIdEqualTo(processInstanceStatisticsQueryVo.getAppId());
        }

        if (CollectionUtil.isNotEmpty(processInstanceStatisticsQueryVo.getAppIds())) {
            criteria.andAppIdIn(processInstanceStatisticsQueryVo.getAppIds());
        }

        if (Objects.nonNull(processInstanceStatisticsQueryVo.getBusiId())) {
            criteria.andBusiIdEqualTo(processInstanceStatisticsQueryVo.getBusiId());
        }


        if (StringUtils.isNotBlank(processInstanceStatisticsQueryVo.getModelKey())) {
            criteria.andModelKeyLike("%" + processInstanceStatisticsQueryVo.getModelKey() + "%");
        }

        if (StringUtils.isNotBlank(processInstanceStatisticsQueryVo.getModelName())) {
            criteria.andModelNameLike("%" + processInstanceStatisticsQueryVo.getModelName() + "%");
        }

        if (StringUtils.isNotBlank(processInstanceStatisticsQueryVo.getProcessInstanceId())) {
            criteria.andProcessInstanceIdEqualTo(processInstanceStatisticsQueryVo.getProcessInstanceId());
        }
        if (StringUtils.isNotBlank(processInstanceStatisticsQueryVo.getStatus())) {
            criteria.andStatusEqualTo(processInstanceStatisticsQueryVo.getStatus());
        }

        if (Objects.nonNull(processInstanceStatisticsQueryVo.getStartTime()) && Objects.nonNull(processInstanceStatisticsQueryVo.getEndTime())) {
            criteria.andStartTimeGreaterThanOrEqualTo(processInstanceStatisticsQueryVo.getStartTime());
            criteria.andStartTimeLessThanOrEqualTo(processInstanceStatisticsQueryVo.getEndTime());
        }

        if (CollectionUtils.isNotEmpty(processInstanceStatisticsQueryVo.getProcessDefinitionIds())) {
            criteria.andProcessDefinitionIdIn(new ArrayList<>(processInstanceStatisticsQueryVo.getProcessDefinitionIds()));
        }

        if (CollectionUtils.isNotEmpty(processInstanceStatisticsQueryVo.getProcessInstanceIds())) {
            criteria.andProcessInstanceIdIn(new ArrayList<>(processInstanceStatisticsQueryVo.getProcessInstanceIds()));
        }

        if (CollectionUtils.isNotEmpty(processInstanceStatisticsQueryVo.getLinkStatuses())) {
            criteria.andLinkStatusIn(processInstanceStatisticsQueryVo.getLinkStatuses());
        }

        return getPageableResult(getProcessInstanceTraces(query));
    }

    @Override
    public List<FlowProcessInstanceTraceVo> getProcessInstanceTracesWithoutUserCheck(List<String> processInstanceIsList) {
        FlowProcessInstanceTraceExample query = new FlowProcessInstanceTraceExample();
        FlowProcessInstanceTraceExample.Criteria criteria = query.createCriteria();
        criteria.andProcessInstanceIdIn(processInstanceIsList);
        List<FlowProcessInstanceTrace> flowProcessInstanceTraceList = getProcessInstanceTraces(query);
        return convert(flowProcessInstanceTraceList);
    }

    public List<FlowProcessInstanceTrace> getProcessInstanceTraces(FlowProcessInstanceTraceExample query) {
        if (Objects.isNull(query)) {
            return null;
        }
        return flowProcessInstanceTraceDAO.selectByExample(query);
    }

    @Override
    public List<FlowProcessInstanceTraceForMonitorVo> list(ProcessInstanceQueryVo processInstanceQueryVo) throws ParseException {
        if (processInstanceQueryVo.getNeedCheckAuth()&&  catalogueService.checkTenantAuthorize(processInstanceQueryVo)) {
            return Collections.emptyList();
        }
        //PageHelper.startPage(processInstanceQueryVo.getPageNum(), processInstanceQueryVo.getPageSize(), true);
        FlowProcessInstanceTraceExample query = new FlowProcessInstanceTraceExample();
        FlowProcessInstanceTraceExample.Criteria criteria = query.createCriteria();

        if (Objects.nonNull(processInstanceQueryVo.getTenantId())) {
            criteria.andTenantIdEqualTo(processInstanceQueryVo.getTenantId());
        }

        if (CollectionUtils.isNotEmpty(processInstanceQueryVo.getTenantIds())) {
            criteria.andTenantIdIn(processInstanceQueryVo.getTenantIds());
        }

        if (Objects.nonNull(processInstanceQueryVo.getAppId())) {
            criteria.andAppIdEqualTo(processInstanceQueryVo.getAppId());
        }

        if (CollectionUtils.isNotEmpty(processInstanceQueryVo.getAppIds())) {
            criteria.andAppIdIn(processInstanceQueryVo.getAppIds());
        }

        if (Objects.nonNull(processInstanceQueryVo.getBusiId())) {
            criteria.andBusiIdEqualTo(processInstanceQueryVo.getBusiId());
        }

        if (CollectionUtils.isNotEmpty(processInstanceQueryVo.getApplyUserNames())) {
            criteria.andStarterNameIn(processInstanceQueryVo.getApplyUserNames());
        }

        if (StringUtils.isNotBlank(processInstanceQueryVo.getStatus())) {
            criteria.andStatusEqualTo(processInstanceQueryVo.getStatus());
        }

        if (StringUtils.isNotBlank(processInstanceQueryVo.getLinkStatus())) {
            criteria.andLinkStatusEqualTo(processInstanceQueryVo.getLinkStatus());
        }

        if (Objects.nonNull(processInstanceQueryVo.getVersion())) {
            criteria.andVersionEqualTo(processInstanceQueryVo.getVersion());
        }

        if (StringUtils.isNotBlank(processInstanceQueryVo.getModelName())) {
            String modelName=processInstanceQueryVo.getModelName().trim();
            Pattern pattern=Pattern.compile("[0-9]*");
            if(pattern.matcher(modelName).matches()){   //当传入的modelName全部为数字时 默认其为流程单号
               criteria.andSerialNumLike("%"+modelName+"%");
            }
            else{
                criteria.andModelNameLike("%" + processInstanceQueryVo.getModelName() + "%");
            }

        }
        if (CollectionUtils.isNotEmpty(processInstanceQueryVo.getModelKeys())) {
            criteria.andModelKeyIn(processInstanceQueryVo.getModelKeys());
        }

        if (StringUtils.isNotBlank(processInstanceQueryVo.getTimeStart()) && StringUtils.isNotBlank(processInstanceQueryVo.getTimeEnd())) {
            criteria.andStartTimeBetween(DateUtils.parseDate(processInstanceQueryVo.getTimeStart(), "yyyy-MM-dd HH:mm:ss"), DateUtils.parseDate(processInstanceQueryVo.getTimeEnd(), "yyyy-MM-dd HH:mm:ss"));
        }

        if(StringUtils.isNotBlank(processInstanceQueryVo.getEndTimeStart()) && StringUtils.isNotBlank(processInstanceQueryVo.getEndTimeEnd())){
            if(StringUtils.isBlank(processInstanceQueryVo.getLinkStatus()) || "END".equals(processInstanceQueryVo.getLinkStatus())){
                criteria.andLinkStatusEqualTo("END");
                criteria.andUpdateTimeBetween(DateUtils.parseDate(processInstanceQueryVo.getEndTimeStart(), "yyyy-MM-dd HH:mm:ss"), DateUtils.parseDate(processInstanceQueryVo.getEndTimeEnd(), "yyyy-MM-dd HH:mm:ss"));
            }
        }

        // 优先按照用户输入的流程实例ID进行查询
        String processInstanceIdStr = processInstanceQueryVo.getProcessInstanceIdStr();
        List<String> instanceIds1=new ArrayList<>();
        if(StringUtils.isNotBlank(processInstanceIdStr)) {
            String[] processInstanceIdArr = processInstanceIdStr.split(",");
            List<String> tempInstances=new ArrayList<>();
            if(processInstanceIdArr != null && processInstanceIdArr.length > 0) {

                for (String processInstanceId : processInstanceIdArr) {
                    tempInstances.add(processInstanceId);
                }
                //如果输入的“节点名称” 或者 “节点编码” 不同时为空
                if(StringUtils.isNotBlank(processInstanceQueryVo.getCurrentNodeName()) || StringUtils.isNotBlank(processInstanceQueryVo.getCurrentNodeCode())){
                     instanceIds1=getInstancesIdByNode(processInstanceQueryVo.getCurrentNodeName(),processInstanceQueryVo.getCurrentNodeCode(),tempInstances);
                    //criteria.andProcessInstanceIdIn(InstanceIds);
                }
                else{
                    instanceIds1.addAll(tempInstances);
                }
                instanceIds1.removeAll(Collections.singleton(null));
                if(instanceIds1.size()==0){
                    log.info("according to processInstance or currentNodeName or currentNodeCode, the system cannot find any processInstanceId");
                    return null;
                }
            }
        }
        else{

            if(StringUtils.isNotBlank(processInstanceQueryVo.getCurrentNodeName()) || StringUtils.isNotBlank(processInstanceQueryVo.getCurrentNodeCode())){
                instanceIds1=getInstancesIdByNode(processInstanceQueryVo.getCurrentNodeName(),processInstanceQueryVo.getCurrentNodeCode(),null);
                //criteria.andProcessInstanceIdIn(InstanceIds);
                instanceIds1.removeAll(Collections.singleton(null));
                if(instanceIds1.size()==0){
                    log.info("according to currentNodeName or currentNodeCode, the system cannot find any processInstanceId");
                    return null;
                }
            }

        }
        //如果用户输入的当前任务处理人不为空
        List<String> processInstanceId=new ArrayList<>();
        if(CollectionUtils.isNotEmpty(processInstanceQueryVo.getOperatorUserNames())){
            List<String> operator=processInstanceQueryVo.getOperatorUserNames();
            log.info("the input operator: {}",operator);

            for(int i=0;i<operator.size();i++) {
                //User user = userRepository.getUserByName(operator.get(i));
                List<User> userResult=userRepository.getUserByNameFromUserCenter(operator.get(i));
                log.info("get information from getUserByNameFromUserCenter：{}",userResult);
                if (Objects.isNull(userResult)){
                    continue;
                }
                String handle=operator.get(i);
                userResult.forEach(item->{
                    User user = userService.getFullUserInfo(item.getUserId());
                    if (user == null) {
                        log.info("查询到 {} 的用户信息为空",handle);
                    }
                    else {
                        log.info("查询到 {} 的用户信息为 {}",handle, user);
                        FlowExecutionQueryVo flowExecutionQueryVo = new FlowExecutionQueryVo();
                        flowExecutionQueryVo.setAssignee(user.getUserId());
                        if(CollectionUtils.isNotEmpty(flowExecutionQueryDAO.selectAssign(flowExecutionQueryVo))){
                            processInstanceId.addAll(flowExecutionQueryDAO.selectAssign(flowExecutionQueryVo));
                        }
                        else{
                            log.info("从act_ru_task表中查询到 {} 的待审批任务为空(assign)",handle);
                        }
                        if(CollectionUtils.isNotEmpty(flowExecutionQueryDAO.selectCandidate(flowExecutionQueryVo))){
                            processInstanceId.addAll(flowExecutionQueryDAO.selectCandidate(flowExecutionQueryVo));
                        }
                        else{
                            log.info("从flow_task_trace表中查询到 {} 的待审批任务为空(candidate_users)",handle);
                        }
                        List<String> orgs=new ArrayList<>();
                        if(user.getOrgInfos()!=null){
                            user.getOrgInfos().forEach(it->{
                                if(it==null){
                                    return;
                                }
                                orgs.add(it.getOrgCode());
                            });
                            log.info("{} 所在的组织:{}",user.getUserName(), orgs);
                        }
                        List<String> roles=new ArrayList<>();
                        if(user.getRoleInfos()!=null){
                            user.getRoleInfos().forEach(it->{
                                if(it==null){
                                    return;
                                }
                                roles.add(it.getRoleCode());
                            });
                            log.info("{} 所在的角色:{}",user.getUserName(), roles);
                        }
                        List<String> positions=new ArrayList<>();
                        if(user.getPositionInfos()!=null){
                            user.getPositionInfos().forEach(it->{
                                if(it==null){
                                    return;
                                }
                                positions.add(it.getPositionCode());
                            });
                            log.info("{} 所在的岗位：{}",user.getUserName(),positions);
                        }
                        List<String> tempInstances=flowTaskTraceDAO.getInstanceIdByUserIdAndGroupId(user.getUserCode(),roles,orgs,positions);
                        if(CollectionUtils.isNotEmpty(tempInstances)){
                            processInstanceId.addAll(tempInstances);
                        }else{
                            log.info("从act_ru_identityLink表中查询到 {} 的待审批任务为空",handle);
                        }
                    }
                });
            }
            log.info("根据审批人获取的流程实例id:{}",processInstanceId);
            processInstanceId.removeAll(Collections.singleton(null));
            if(processInstanceId.size()==0) {
                log.info("according to operator, the system cannot find any processInstanceId");
                return null;
            }
        }
        List<String> processInstanceIds = new ArrayList<>(); //存储按照输入的流程实例、当前节点名称、当前节点编码、审批人筛选以后的结果
        if(instanceIds1.size()!=0 && processInstanceId.size()!=0 ){
            for(int i=0;i<instanceIds1.size();i++){
                if(processInstanceId.contains(instanceIds1.get(i))){
                    processInstanceIds.add(instanceIds1.get(i));
                    log.info("情形1：{}",processInstanceIds);
                }
            }
            if(processInstanceIds==null || processInstanceIds.size()==0 ){
                return null;
            }
            criteria.andProcessInstanceIdIn(processInstanceIds);
        }
        if(instanceIds1.size()==0 && processInstanceId.size()!=0){
            processInstanceIds.addAll(processInstanceId);
            log.info("情形2：{}",processInstanceIds);
            criteria.andProcessInstanceIdIn(processInstanceIds);
        }
        if(instanceIds1.size()!=0 && processInstanceId.size()==0){
            processInstanceIds.addAll(instanceIds1);
            log.info("情形3：{}",processInstanceIds);
            criteria.andProcessInstanceIdIn(processInstanceIds);
        }
        query.setOrderByClause(" create_time desc");
        PageHelper.startPage(processInstanceQueryVo.getPageNum(), processInstanceQueryVo.getPageSize(), true);
        return getPageableResult1(getProcessInstanceTraces(query));

    }

    /**
     * 根据节点名称 or 节点编码  or 流程实例id 从flow_task_trace表中查找流程实例id
     * @param nodeName
     * @param nodeCode
     * @param processInstanceIds
     * @return
     */
   private List<String> getInstancesIdByNode(String nodeName,String nodeCode,List<String> processInstanceIds){
       List<String> InstanceIds=new ArrayList<>();
       List<FlowTaskTrace> instanceIds=flowTaskTraceDAO.queryProcessInstanceIdByTaskNameAndTaskCode(nodeName,nodeCode,processInstanceIds);
       if(CollectionUtils.isNotEmpty(instanceIds)){
           instanceIds.forEach(it->{
               if(InstanceIds.size()==0){
                   InstanceIds.add(it.getProcessInstanceId());
                   return;
               }
               if(InstanceIds.contains(it.getProcessInstanceId())){
                   return;
               }
               InstanceIds.add(it.getProcessInstanceId());
           });
       }
       return InstanceIds;
   }
    @Override
    public List<FlowProcessInstanceTraceVo> list(HttpProcessInstanceQueryVo processInstanceQueryVo) {
        PageHelper.startPage(processInstanceQueryVo.getPageNum(), processInstanceQueryVo.getPageSize());
        FlowProcessInstanceTraceExample query = new FlowProcessInstanceTraceExample();
        FlowProcessInstanceTraceExample.Criteria criteria = query.createCriteria().andStarterIdEqualTo(processInstanceQueryVo.getStarterId());
        if (StrUtil.isNotBlank(processInstanceQueryVo.getProcessInstanceId())) {
            criteria.andProcessInstanceIdEqualTo(processInstanceQueryVo.getProcessInstanceId());
        }
        if(CollectionUtils.isNotEmpty(processInstanceQueryVo.getProcessInstanceIds())) {
            criteria.andProcessInstanceIdIn(processInstanceQueryVo.getProcessInstanceIds());
        }
        String orderByClause = processInstanceQueryVo.getOrderByClause();
        if(StringUtils.isNotEmpty(orderByClause) && StringUtils.isNotEmpty(orderByClause.trim())){
            query.setOrderByClause(orderByClause);
        }else{
            query.setOrderByClause("create_time desc");
        }
        return getPageableResult(getProcessInstanceTraces(query));
    }


    @Override
    public void update(List<FlowProcessInstanceTraceVo> processInstanceTraces) {
        Date updateTime = new Date();
        for (FlowProcessInstanceTraceVo vo : processInstanceTraces) {
            FlowProcessInstanceTrace entity = new FlowProcessInstanceTrace();
            BeanUtils.copyProperties(vo, entity);
            entity.setUpdateTime(updateTime);
            flowProcessInstanceTraceDAO.updateByPrimaryKeySelective(entity);
        }
    }

    /**
     * 更新实例
     *
     * @param processInstanceTrace 实例信息
     */
    @Override
    public void  update(FlowProcessInstanceTraceVo processInstanceTrace){
        Date updateTime = new Date();
        FlowProcessInstanceTrace entity = new FlowProcessInstanceTrace();
        BeanUtils.copyProperties(processInstanceTrace, entity);
        entity.setUpdateTime(updateTime);
        flowProcessInstanceTraceDAO.updateByPrimaryKeySelective(entity);
    }

    @Override
    public void updateLinkStatusToRunning(String processInstanceId) {
        FlowProcessInstanceTraceVo vo = getProcessInstanceTraceByProcessInstanceId(processInstanceId);
        if (Objects.isNull(vo)) {
            return;
        }

        if (!Objects.equals(vo.getStatus(), ProcessInstanceStatusEnum.PAUSE.getCode())) {
            vo.setLinkStatus(ProcessInstanceLinkStatusEnum.RUNNING.getCode());
        }
        vo.setUpdateTime(new Date());
        FlowProcessInstanceTrace entity = new FlowProcessInstanceTrace();
        BeanUtils.copyProperties(vo, entity);
        flowProcessInstanceTraceDAO.updateByPrimaryKeySelective(entity);
    }

    @Override
    public void updateLinkStatusToEnd(String processInstanceId) {
        FlowProcessInstanceTraceVo vo = getProcessInstanceTraceByProcessInstanceId(processInstanceId);
        if (Objects.isNull(vo) || isDone(vo)) {
            return;
        }
        if (!Objects.equals(vo.getStatus(), ProcessInstanceStatusEnum.PAUSE.getCode())) {
            vo.setLinkStatus(ProcessInstanceLinkStatusEnum.END.getCode());
        }
        vo.setUpdateTime(new Date());
        FlowProcessInstanceTrace entity = new FlowProcessInstanceTrace();
        BeanUtils.copyProperties(vo, entity);
        flowProcessInstanceTraceDAO.updateByPrimaryKeySelective(entity);
    }

    @Override
    public void updateStatusToTimeout(String processInstanceId) {
        FlowProcessInstanceTraceVo vo = getProcessInstanceTraceByProcessInstanceId(processInstanceId);
        if (Objects.isNull(vo) || isDone(vo)) {
            return;
        }
        vo.setStatus(ProcessInstanceStatusEnum.TIMEOUT.getCode());
        vo.setFlag(2);
        vo.setUpdateTime(new Date());
        FlowProcessInstanceTrace entity = new FlowProcessInstanceTrace();
        BeanUtils.copyProperties(vo, entity);
        flowProcessInstanceTraceDAO.updateByPrimaryKeySelective(entity);
    }

    @Override
    public void updateStatusToWarning(String processInstanceId) {
        FlowProcessInstanceTraceVo vo = getProcessInstanceTraceByProcessInstanceId(processInstanceId);
        if (Objects.isNull(vo) || isDone(vo)) {
            return;
        }
        vo.setStatus(ProcessInstanceStatusEnum.WARNING.getCode());
        vo.setFlag(1);
        vo.setUpdateTime(new Date());
        FlowProcessInstanceTrace entity = new FlowProcessInstanceTrace();
        BeanUtils.copyProperties(vo, entity);
        flowProcessInstanceTraceDAO.updateByPrimaryKeySelective(entity);
    }

    @Override
    public void updateStatusToError(String processInstanceId) {
        this.updateStatus(processInstanceId, ProcessInstanceStatusEnum.ERROR.getCode());
    }

    @Override
    public void updateStatus(String processInstanceId, String status) {
        FlowProcessInstanceTraceVo vo = getProcessInstanceTraceByProcessInstanceId(processInstanceId);
        if (Objects.isNull(vo) || isDone(vo)) {
            return;
        }
        vo.setStatus(status);
        vo.setUpdateTime(new Date());
        FlowProcessInstanceTrace entity = new FlowProcessInstanceTrace();
        BeanUtils.copyProperties(vo, entity);
        flowProcessInstanceTraceDAO.updateByPrimaryKeySelective(entity);
    }

    /**
     * 更新流程模板信息
     *
     * @param processInstanceId 实例id
     * @param newProcDefId 新流程模板信息
     */
    @Override
    public void updateProcDefId(String processInstanceId,String newProcDefId,Integer version){
        FlowProcessInstanceTraceVo vo = getProcessInstanceTraceByProcessInstanceId(processInstanceId);
        if (Objects.isNull(vo) ) {
            return;
        }
        vo.setProcessDefinitionId(newProcDefId);
        vo.setUpdateTime(new Date());
        vo.setVersion(version);
        FlowProcessInstanceTrace entity = new FlowProcessInstanceTrace();
        BeanUtils.copyProperties(vo, entity);
        flowProcessInstanceTraceDAO.updateByPrimaryKeySelective(entity);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelProcessInstance(String processInstanceId) {
        this.updateLinkStatusToEnd(processInstanceId);
        this.updateStatus(processInstanceId, ProcessInstanceStatusEnum.END.getCode());
        taskTraceRepository.updateRunningTaskStatusAfterProcessInstanceCancel(processInstanceId);
    }

    private boolean isDone(FlowProcessInstanceTraceVo entity) {
        return Objects.equals(entity.getLinkStatus(), ProcessInstanceLinkStatusEnum.END.getCode());
    }

    private List<FlowProcessInstanceTraceVo> getPageableResult(List<FlowProcessInstanceTrace> flowProcessInstanceTraces) {
        PageInfo<FlowProcessInstanceTrace> pageInfo = new PageInfo<>(flowProcessInstanceTraces);
        Page<FlowProcessInstanceTraceVo> result = null;
        try {
            result = new Page<>();
            result.setPageNum(pageInfo.getPageNum()).setPageSize(pageInfo.getPageSize()).addAll(convert(flowProcessInstanceTraces));
            result.setTotal(pageInfo.getTotal());
            return result;
        } finally {
            if (Objects.nonNull(result)) {
                result.close();
            }
        }

    }
    //为实例查询添加分页
    private List<FlowProcessInstanceTraceForMonitorVo> getPageableResult1(List<FlowProcessInstanceTrace> flowProcessInstanceTraces) {
        PageInfo<FlowProcessInstanceTrace> pageInfo = new PageInfo<>(flowProcessInstanceTraces);
        Page<FlowProcessInstanceTraceForMonitorVo> result = null;
        try {
            result = new Page<>();
            result.setPageNum(pageInfo.getPageNum()).setPageSize(pageInfo.getPageSize()).addAll(queryOperateAndCurrentNode(flowProcessInstanceTraces));
            result.setTotal(pageInfo.getTotal());
            return result;
        } finally {
            if (Objects.nonNull(result)) {
                result.close();
            }
        }
    }

    private FlowProcessInstanceTraceVo convert(FlowProcessInstanceTrace entity) {
        if (Objects.isNull(entity)) {
            return null;
        }

        FlowProcessInstanceTraceVo result = new FlowProcessInstanceTraceVo();
        BeanUtils.copyProperties(entity, result);
        return result;
    }

    private List<FlowProcessInstanceTraceVo> convert(List<FlowProcessInstanceTrace> sources) {
        return sources.stream().map(this::convert).collect(Collectors.toList());
    }

   //为记录添加当前节点信息和当前任务处理人 
    public List<FlowProcessInstanceTraceForMonitorVo> queryOperateAndCurrentNode(List<FlowProcessInstanceTrace> sources){
        List<FlowProcessInstanceTraceForMonitorVo> result=new ArrayList<>();
        sources.forEach(item->{
            FlowProcessInstanceTraceForMonitorVo flowProcessInstanceTraceForMonitorVo=new FlowProcessInstanceTraceForMonitorVo();
            BeanUtils.copyProperties(item,flowProcessInstanceTraceForMonitorVo);
            FlowExecutionQueryVo flowExecutionQueryVo = new FlowExecutionQueryVo();
            flowExecutionQueryVo.setProcessInstanceId(flowProcessInstanceTraceForMonitorVo.getProcessInstanceId());
            String operator=queryOperatorByProcessInstanceId(flowExecutionQueryVo);
            if(StringUtils.isNotBlank(operator)){
                log.info("get operator from flow_task_trace or act_ru_task or act_ru_identity:{}",operator);
                flowProcessInstanceTraceForMonitorVo.setOperator(operator);
            }
            else{
                if(CollectionUtils.isNotEmpty(flowExecutionQueryDAO.queryCandidate(flowExecutionQueryVo))){
                    String candidate=flowExecutionQueryDAO.queryCandidate(flowExecutionQueryVo).get(0);
                    if(StringUtils.isNotBlank(candidate)){
                        log.info("get candidates from flow_task_trace: {}",candidate);
                        flowProcessInstanceTraceForMonitorVo.setOperator(handleCandidate(candidate));
                    }
                }
            }
            flowExecutionQueryVo.setFlowTaskStatus(TaskLinkStatusEnum.TODO.getCode());
            List<FlowExecutionQueryInfo> processInstanceList = flowExecutionQueryDAO.getProcessInstanceList(flowExecutionQueryVo);
            if(CollectionUtils.isNotEmpty(processInstanceList)){
                List<String> nodeNames = processInstanceList.stream().map(FlowExecutionQueryInfo::getTaskName).distinct().collect(Collectors.toList());
                flowProcessInstanceTraceForMonitorVo.setCurrentNode(String.join(";", nodeNames));
                List<Map<String, Object>> currentNodeInfo = processInstanceList.stream().map(element -> {
                    Map<String, Object> map = new HashMap<>();
                    map.put("name", element.getTaskName());
                    map.put("id", element.getActivityId());
                    map.put("taskId", element.getTaskId());
                    return map;
                }).collect(Collectors.toList());
                flowProcessInstanceTraceForMonitorVo.setCurrentNodeInfo(currentNodeInfo);
            }
            if (ProcessInstanceStatusEnum.ERROR.getCode().equals(flowProcessInstanceTraceForMonitorVo.getStatus())) {
                List<String> messageList = flowProcessInstanceOperateTraceRepository.queryFlowProcessInstanceOperateTraceListByProcessInstanceIdAndAction(flowProcessInstanceTraceForMonitorVo.getProcessInstanceId(), ProcessInstanceStatusEnum.ERROR.getCode()).stream()
                        .map(FlowProcessInstanceOperateTraceVo::getMessage).collect(Collectors.toList());
                flowProcessInstanceTraceForMonitorVo.setErrorMessage(messageList);
            }
            result.add(flowProcessInstanceTraceForMonitorVo);
        });
        return result;
    }
    public String handleCandidate(String candidate){
        StringBuilder re=new StringBuilder("");
        String result1=new String();
        if(StringUtils.isNotBlank(candidate)){
            String result[]=candidate.trim().split(",");
            for(int i=0;i<result.length;i++){
                User user=userRepository.getUserWithOrgByCodeFromUserCenter(result[i]);
                if(user!=null){
                    re.append(user.getUserName()+";");
                }
            }
            result1=String.valueOf(re);
            if(result1.endsWith(";")){
                result1=result1.substring(0,result1.length()-1);
            }
            return result1;
        }
        return null;
    }
    private String queryOperatorByProcessInstanceId(FlowExecutionQueryVo flowExecutionQueryVo){
        List<String> result=new ArrayList<>();
        StringBuilder operatorInfo=new StringBuilder();
        //从flow_task_trace表中根据流程实例id查找当前任务处理人
        List<String> flowOperator=flowTaskTraceDAO.queryAssignFromFlowTaskTrace(flowExecutionQueryVo.getProcessInstanceId()).stream().distinct().collect(Collectors.toList());
        flowOperator.removeAll(Collections.singleton(null));
        if(CollectionUtils.isNotEmpty(flowOperator)){
            result.addAll(flowOperator);
            log.info("get operator from flow_task_trace:{}",result);
//            List<String> temp=result.stream().distinct().collect(Collectors.toList());
//            return String.join(";",temp);

        }
        //从act_ru_task表中根据流程实例id查找当前任务处理人
        List<String> actAssign=flowExecutionQueryDAO.queryAssign(flowExecutionQueryVo).stream().distinct().collect(Collectors.toList());
        actAssign.removeAll(Collections.singleton(null));
        if(CollectionUtils.isNotEmpty(actAssign)){
            actAssign.forEach(it->{
                User user=userRepository.getUserWithOrgByCodeFromUserCenter(it);
                log.info("get infromation from getUserWithOrgByCodeFromUserCenter-{}：{} ",it,user);
                if(user!=null){
                    result.add(user.getUserName());
                }
            });
//            List<String> temp=result.stream().distinct().collect(Collectors.toList());
//            log.info("get operator from act_ru_task:{}",temp);
//            return String.join(";",temp);

        }
        List<FlowExecutionQueryLink> linkAssign=flowExecutionQueryDAO.queryIdentityLinkByProcessInstanceId(flowExecutionQueryVo);
        linkAssign.removeAll(Collections.singleton(null));
        final List<String> test= Arrays.asList("STA", "participant", "starter", "candidate");
        if(CollectionUtils.isNotEmpty(linkAssign)){
            linkAssign.forEach(it->{
                if(test.contains(it.getType())){
                    //User user=userRepository.getUserWithOrgByCodeFromUserCenter(it.getUserId());
                    User user=userService.getFullUserInfo(it.getUserId());
                    if(user!=null)
                       result.add(user.getUserName());
                    return;
                }
                //List<User> users=new ArrayList<>();
                if("ORG".equals(it.getType())){
                    if(it.getGroupId()!=null && it.getGroupId()!=""){
                        //users=userRepository.listUserByOrgCode(it.getGroupId());
                        String orgName=userRepository.getOrgNameById(it.getGroupId());
                        operatorInfo.append(orgName+"（组织）;");
                    }
                }
                if("ROL".equals(it.getType())){
                    if(it.getGroupId()!=null && it.getGroupId()!=""){
                        //users=userRepository.listUserByRoleId(it.getGroupId());
                        String roleName=userRepository.getRoleNameById(it.getGroupId());
                        operatorInfo.append(roleName+"（角色）;");
                    }
                }
                if("POSITION".equals(it.getType())){
                    if(it.getGroupId()!=null && it.getGroupId()!=""){
                        //users=userRepository.getUserListByPositionId(it.getGroupId());
                        String positionName=userRepository.getPositionDetailById(it.getGroupId());
                        operatorInfo.append(positionName+"（岗位）;");
                    }
                }
//                for(int i=0;i<users.size();i++){
//                    result.add(users.get(i).getUserName());
//                }
            });
        }
        log.info("role-position-org information:{}",operatorInfo.toString());
        if(CollectionUtils.isNotEmpty(result)){
            List<String> temp=result.stream().distinct().collect(Collectors.toList());
            log.info("get operator from act_ru_identityLink:{}",temp);
            return String.join(";",temp)+";"+operatorInfo.toString();
        }
        return operatorInfo.toString();


    }
    /**
     * 根据流程id，查询流程状态是否结束
     */
    @Override
    public String queryFlowStateByFlowId(String flowId){
        String message = "";
        //根据流程id，查询流程是否已经结束
        List<String> flowTaskTrace=flowTaskTraceDAO.queryAssignFromFlowTaskTrace(flowId);
        if (flowTaskTrace.size()>0){
            message = "NORMAL";
        } else {
            message = "END";
        }
        return message;


    }

}
